package com.jake.data_structure_learning.hash.map;

public class MyHashMap {
    private int size;
    private Object[] obj;

    /**
     * Initialize your data structure here.
     */
    public MyHashMap() {
        size = 16;
        obj = new Object[size];
    }

    /**
     * value will always be non-negative.
     */
    public void put(int key, int value) {
        int index = this.getHashIndex(key);
        Object object = obj[index];
        if (object == null) {
            Node node = new Node(key, value);
            Node[] nodes = new Node[]{node};
            obj[index] = nodes;
        } else {
            Node[] nodes = (Node[]) object;
            boolean flag = false;
            for (int i = 0; i < nodes.length; i++) {
                if (nodes[i].getKey() == key) {
                    nodes[i] = new Node(key, value);
                    flag = true;
                }
            }
            if (!flag) {
                Node[] newNode = new Node[nodes.length + 1];
                for (int i = 0; i < nodes.length; i++) {
                    newNode[i] = nodes[i];
                }
                newNode[nodes.length] = new Node(key, value);
                obj[index] = newNode;
            }
        }
    }

    /**
     * Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key
     */
    public int get(int key) {
        int index = this.getHashIndex(key);
        Object object = obj[index];
        if (object == null) {
            return -1;
        } else {
            Node[] nodes = (Node[]) object;
            for (Node node : nodes) {
                if (node.getKey() == key) {
                    return node.getValue();
                }
            }
        }

        return -1;
    }

    /**
     * Removes the mapping of the specified value key if this map contains a mapping for the key
     */
    public void remove(int key) {
        int index = this.getHashIndex(key);
        Object object = obj[index];
        if (object == null) {
            return;
        } else {
            Node[] nodes = (Node[]) object;
            int slow = 0;
            for (int fast = 0; fast < nodes.length; fast++) {
                Node node = nodes[fast];
                if (node.getKey() != key) {
                    nodes[slow++] = nodes[fast];
                }
            }
            if (slow < nodes.length) {
                Node[] newNode = new Node[slow];
                for (int i = 0; i < slow; i++) {
                    newNode[i] = nodes[i];
                }
                obj[index] = newNode;
            }
        }
    }

    private int getHashIndex(int key) {
        return key % size;
    }

    private class Node {
        private int key;
        private int value;

        public Node(int key, int value) {
            this.key = key;
            this.value = value;
        }

        public int getKey() {
            return key;
        }

        public void setKey(int key) {
            this.key = key;
        }

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }
    }
}
